import http = require("http");
import https = require('https');
import urlParse = require("url");

/**
 * 
 * 
 * @export
 * @class MPJRequest
 */
export class cRequest implements ICRequest {
    static Current: cRequest = new cRequest();
    /**
     * Http get 请求，连锁店铺数据的获取兼容需要在 headers 中添加 storeID
     * 
     * @template T 
     * @param {any} url 请求路径
     * @param {any} [headers] 请求头
     * @returns {T} 
     * @memberof MPJRequest
     */
    Get<T>(url, headers?): Promise<T> {
        return <any>this.Request<T>(url, "GET", null, headers);
    }
    /**
     * 
     * 
     * @param {string} url
     * @param {any} data
     * @returns
     * 
     * @memberOf MPJRequest
     */
    Put(url: string, data, headers?) {
        return this.Request(url, "PUT", data, headers);
    }

    Delete(url: string, data?, headers?) {
        if (data) {
            url += '?' + this.ToQueryString(data);
        }
        return this.Request(url, "DELETE", null, headers);
    }

    /**
     * 获取带参数的url地址
     * 
     * @param {string} relativePath 接口url地址
     * @param {any} params 地址参数
     * @returns {string}
     * 
     * @memberOf MPJRequest
     */
    // GetUrl(relativePath: string, params?): string {
    //     if (Array.isArray(relativePath)) {
    //         relativePath = relativePath.join('/');
    //     }
    //     if (relativePath[0] == '/') {
    //         relativePath = relativePath.substring(1);
    //     }
    //     var url = [config.cloudHost, relativePath].join('/');
    //     if (params) {
    //         url += '?' + this.ToQueryString(params);
    //     }
    //     return url;
    // }

    /**
     * 
     * 
     * @param {string} url
     * @param {any} data
     * @returns
     * 
     * @memberOf MPJRequest
     */
    Post<T>(url: string, data, headers?, encoding?: 'utf8' | 'binary'): T {
        return <any>this.Request<T>(url, "POST", data, headers, encoding);
    }

    private Request<T>(url: string, method: string, data?, headers?, encoding?: 'utf8' | 'binary'): Promise<T> {
        return new Promise((resovle, reject) => {
            let content;
            if (data) {
                if (data instanceof Object) {
                    content = JSON.stringify(data);
                }
                else {
                    content = data;
                }
            }
            else {
                content = "";
            }
            let urlObject = urlParse.parse(url);

            let options = {
                hostname: urlObject.hostname,
                port: urlObject.port,
                path: url,
                method: method,
                headers: {
                    "token": 'bd5ac36a4fc5ee1d755793acad5e7d7c',
                    'Content-Type': 'application/json',
                    "Content-length": Buffer.byteLength(content)
                }
            };

            if (headers) {
                for (let key in headers) {
                    options.headers[key] = headers[key];
                }
            }

            let client;
            if (process.env.protocol == 'https') {
                client = https;
            }
            else {
                client = http;
            }
            if (urlObject.protocol) {
                if (urlObject.protocol == "https:") {
                    client = https;
                }
                else if (urlObject.protocol == "http:") {
                    client = http;
                }
            }

            let req = client.request(options, function (res: any) {
                if (encoding) {
                    res.setEncoding(encoding);
                }
                else {
                    res.setEncoding('utf8');
                }

                res.data = '';
                res.on('data', function (chunk: any) {
                    res.data += chunk;
                });

                res.on('end', function () {
                    if (res.statusCode && res.statusCode >= 400 && res.statusCode <= 503) {
                        let errObject;
                        try {
                            errObject = JSON.parse(res.data);
                            errObject.statusCode = res.statusCode;
                        } catch (error) {
                            errObject = res.data;
                        }
                        reject(errObject);
                    } else {
                        let contentType = res.headers['content-type'];
                        if (!contentType) {
                            resovle();
                            return;
                        }
                        if (!contentType.indexOf) {
                            resovle();
                            return;
                        }
                        if (contentType.indexOf('application/json') > -1) {
                            try {
                                let d: any = '';
                                if (res.data) {
                                    d = JSON.parse(res.data);
                                } else {
                                    d = res.data;
                                }
                                resovle(d);
                            }
                            catch (err) {
                                reject(res.data);
                            }
                        }
                        else if (contentType.indexOf('application/octet-stream') > -1
                            || contentType.indexOf('image/jpeg') > -1) {
                            let ctxDisposition = res.headers['content-disposition'];
                            let tmp = ctxDisposition.split(';');
                            let fileName = (tmp[1].split('='))[1];
                            let r: any = {
                                fileName,
                                fileStream: res.data
                            };
                            resovle(r);
                        }
                        else if (contentType.indexOf('text/plain') > -1) {
                            try {
                                let d: any = '';
                                if (res.data) {
                                    d = JSON.parse(res.data);
                                } else {
                                    d = res.data;
                                }
                                resovle(d);
                            }
                            catch (err) {
                                reject(res.data);
                            }
                        }
                    }
                });
            });

            req.on('error', function (e) {
                console.log('problem with request: ' + e.message);
                reject(e);
            });

            // 添加请求超时设置：60 秒
            req.setTimeout(60000, function () {
                this.abort();
            }.bind(req));

            // write data to request body  
            // 这样写防止 socket hang up
            if (method != 'GET') {
                req.write(content);
            }
            req.end();
        });
    }

    private ToQueryString(obj) {
        var str = [];
        for (var p in obj)
            if (obj.hasOwnProperty(p)) {
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            }
        return str.join("&");
    }
}

interface ICRequest {
    Get<T>(url, headers?): Promise<T>;
    Put(url: string, data, headers?);
    // GetUrl(relativePath: string, params?): string;
    Post<T>(url: string, data): Promise<T>;
}